#include "logout.hh"
#include "protocol.hh"
#include <iostream>
#include <thread>
#include <utility>
#include <string.h>
#include <errno.h>
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <mutex>
#include <netinet/in.h>
#include <unistd.h>

#define buffer_size 1024

using namespace std;
class tcp_client_t
{
public:
    tcp_client_t(string addr, uint16_t port)
        : _is_res_printed(true)
    {
        pthread_mutex_init(&_print_lock, nullptr);
        pthread_cond_init(&_print_cond, nullptr);
        // info
        bzero(&_server_addr, sizeof(_server_addr));
        _server_addr.sin_family = AF_INET;
        _server_addr.sin_port = htons(port);
        _server_addr.sin_addr.s_addr = inet_addr(addr.c_str());
        // socket
        _connect_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_connect_socket_fd < 0)
        {
            log_error("creat_connect_socket_error!", SOCKET_CREAT_ERROR);
        }
    }
    ~tcp_client_t()
    {
        pthread_mutex_destroy(&_print_lock);
        pthread_cond_destroy(&_print_cond);
        close(_connect_socket_fd);
    }

public:
    void connect_to_server()
    {
        if (connect(_connect_socket_fd, (const sockaddr *)&_server_addr, sizeof(_server_addr)) < 0)
        {
            log_error("connect_to_server_error!", CONNECT_TO_SERVER_ERROR);
        }
    }
    void interact()
    {
        // tcp -面向连接 视作和远端一对一通讯 此需求场景客户端一个线程够用
        //  1.输入表达式
        //  2.处理表达式 生成请求结构化数据
        //  3.序列化请求 生成有效载荷
        //  4.添加报头 生成报文
        //  5.发送给服务器
        //  6.接收服务器回应报文
        //  7.删除报文提取有效载荷
        //  8.反序列化 生成回应结构化数据
        //  9.done.
        volatile bool quit = false;
        while (!quit)
        {
            // 1
            string input_str;
            cout << "请输入表达式:> ";
            getline(cin, input_str);
            if (input_str == "exit" || input_str == "quit")
            {
                quit = true;
                continue;
            }
            // 2
            auto make_req_ret = make_request(input_str);
            if (make_req_ret.first == false)
            {
                cout << "表达式格式错误,应为: \"a+b\"" << endl;
                continue;
            }
            // 3
            string package = make_req_ret.second.serialize();
            // 4
            encode(package);
            // 5
            write(_connect_socket_fd, package.c_str(), package.size());
            // 6
            char read_buffer[buffer_size];
            bzero(read_buffer, buffer_size);
            ssize_t read_size = read(_connect_socket_fd, read_buffer, buffer_size - 1);
            if (read_size == 0)
            {
                cout << "服务器关闭,quit..." << endl;
                quit = true;
                continue;
            }
            string response_package(read_buffer);
            // 7
            auto decode_ret = decode(response_package);
            if (decode_ret.first == false)
            {
                cout << "decode fail!" << endl;
                continue;
            }
            string payload(decode_ret.second);
            // 8
            response res;
            res.deserialize(payload);
            // done.
            if (res._exit_code)
                cout << "exit_code: " << res._exit_code << endl;
            else
                cout << "result: " << res._result << endl;
        }
    }

private:
    struct thread_argc_struct_t
    {
        thread_argc_struct_t(int fd, tcp_client_t *pthis)
            : _fd(fd), _this(pthis) { ; }
        int _fd;
        tcp_client_t *_this;
    };

    sockaddr_in _server_addr;
    bool _is_res_printed;
    pthread_mutex_t _print_lock;
    pthread_cond_t _print_cond;
    int _connect_socket_fd;
};